/**
 * FileName: NettyClientManager
 * Author: Mr.Wang
 * Date: 2025/10/15 16:47
 * Description:
 * History:
 */
package org.test.device.utils.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import jakarta.annotation.Resource;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;
import org.test.device.config.netty.ClientHandler;
import org.test.device.config.netty.NettyProperties;

import java.nio.charset.StandardCharsets;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 〈一句话功能简述〉<br>
 * 〈netty客户端管理器〉
 * Netty客户端管理器，提供公共的消息发送方法
 * 支持在其他类中直接调用发送消息，自动管理连接
 *
 * @author Mr.Wang
 * @create 2025/10/15
 * @since 1.0.0
 */
@Slf4j
@Getter
@Component
@EnableConfigurationProperties(NettyProperties.class)
public class NettyClientManager {

    @Autowired
    NettyProperties nettyProperties;

    @Resource
    @Qualifier("nettyInitTaskExecutor")
    private TaskExecutor taskExecutor;

    @Autowired
    private ApplicationContext applicationContext;

    // Netty相关组件
    private EventLoopGroup group;
    private Channel channel;  // 与服务器的连接通道
    public static final int MAX_RECONNECT_COUNT = 5;  // 最大重连次数
    private final ReentrantLock lock = new ReentrantLock();  // 确保线程安全

    // 服务器地址和端口（可从配置文件读取）
    private String serverHost;
    private int serverPort;
    private int reconnectDelay;  // 重连延迟时间（秒）
    private int reconnectCount=0;//重连次数

    public NettyClientManager() {}

    /**
     * 初始化配置（在Spring注入完成后执行）
     */
    @PostConstruct
    public void initConfig() {
        this.serverHost = nettyProperties.getServerHost();
        this.serverPort = nettyProperties.getPort();
        this.reconnectDelay = nettyProperties.getReconnectDelay();
        log.info("[NettyClientManager]Netty客户端配置加载完成：{}:{}，重连延迟：{}秒",
                serverHost, serverPort, reconnectDelay);

        // 异步初始化连接（提交到线程池执行）
        asyncInitConnection();
    }
    
        /**
        * @Author Mr.Wang
        * @Description 异步初始化连接（提交到线程池执行）
        * @Date  2025/10/16
        * @Param 
        **/
        public CompletableFuture<Boolean> asyncInitConnection() {
            CompletableFuture<Boolean> future = new CompletableFuture<>();
            taskExecutor.execute(() -> {
                try {
                    boolean result = initConnection();
                    future.complete(result);
                } catch (Exception e) {
                    log.error("异步初始化连接异常", e);
                    future.completeExceptionally(e);
                }
            });
            return future;
        }

    /**
     * 初始化连接（如果未连接则创建连接）
     *
     * @return 是否连接成功
     */
    private boolean initConnection() {
        // 双重检查：已连接则直接返回
        if (isConnected()) {
            return true;
        }
        lock.lock();
        try {
            // 再次检查（防止并发问题）
            if (isConnected()) {
                return true;
            }
            // 校验配置有效性
            if (serverHost == null || serverPort <= 0 || serverPort > 65535) {
                log.error("无效的服务器配置：{}:{}", serverHost, serverPort);
                return false;
            }

            // 关闭旧的EventLoopGroup（如果存在）
            if (group != null) {
                group.shutdownGracefully().addListener(future ->
                        log.info("旧 EventLoopGroup 已异步关闭"));
            }

            group = new NioEventLoopGroup();
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .option(ChannelOption.SO_KEEPALIVE, true)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)  // 连接超时5秒
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ChannelPipeline pipeline = ch.pipeline();
                            // 帧解码器：处理粘包/拆包问题
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(
                                            65535, 0, 4, 0, 4))
                                    // 帧编码器：添加长度字段
                                    .addLast(new LengthFieldPrepender(4))
                                    // 字符串编解码器
                                    .addLast(new StringDecoder(StandardCharsets.UTF_8))
                                    .addLast(new StringEncoder(StandardCharsets.UTF_8))
                                    // 自定义客户端处理器
                                    .addLast(applicationContext.getBean(ClientHandler.class));
                        }
                    });

            // 连接服务器（同步等待结果）
            log.info("[NettyClientManager]正在异步连接Netty服务器：{}:{}", serverHost, serverPort);
            bootstrap.connect(serverHost, serverPort).addListener((ChannelFutureListener) future -> {
                if (future.isSuccess()) {
                    channel = future.channel();
                    reconnectCount=0;
                    log.info("[NettyClientManager]连接Netty服务器成功");
                } else {
                    log.error("[NettyClientManager]连接Netty服务器失败", future.cause());
                    // 连接失败时调度重连
                    scheduleReconnect();
                }
            });
           return true;
        } catch (Exception e) {
            log.error("初始化Netty连接异常", e);
            scheduleReconnect();  // 发生异常时调度重连
            return false;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 发送消息到服务器（异步发送，不等待发送完成）
     *
     * @param message 要发送的消息
     * @return 是否发送成功
     */
    public CompletableFuture<Boolean> asyncSendMessage(String message) {
        log.info("[NettyClientManager]发送消息到服务器：{}", message);
        return asyncSendMessage(message, 3, TimeUnit.SECONDS);  // 默认超时3秒
    }

    /**
     * 发送消息到服务器（带超时时间）
     *
     * @param message 要发送的消息
     * @param timeout 超时时间
     * @param unit    时间单位
     * @return 是否发送成功
     */
    public CompletableFuture<Boolean> asyncSendMessage(String message, long timeout, TimeUnit unit) {
        CompletableFuture<Boolean> future = new CompletableFuture<>();
        taskExecutor.execute(() -> {
            try{
                boolean result=sendMessage(message,timeout, unit);
                future.complete(result);
            }catch (Exception e){
                log.error("[NettyClientManager]发送消息异常，消息：{}", message, e);
                future.completeExceptionally(e);
            }
        });
        return future;
    }

    /**
    * @Author Mr.Wang
    * @Description 实际发送消息的逻辑，包括校验消息是否为空、检查连接状态、异步发送并等待超时
    * @Param message 要发送的消息
    * @Param timeout 超时时间
    * @Param unit 时间单位
    * @Return 是否发送成功
    **/
    private boolean sendMessage(String message, long timeout, TimeUnit unit) {
        if (message == null || message.isEmpty()) {
            log.warn("[NettyClientManager]消息不能为空");
            return false;
        }

        if (!isConnected()) {
            log.error("[NettyClientManager]连接未建立，无法发送消息：{}", message);
            // 异步触发重连
            asyncInitConnection();
            return false;
        }

        try {
            // 异步发送并等待超时
            ChannelFuture future = channel.writeAndFlush(message);
            boolean success = future.await(timeout, unit);
            if (success && future.isSuccess()) {
                log.info("[NettyClientManager]消息发送成功：{}", message);
                return true;
            } else {
                log.error("[NettyClientManager]消息发送超时或失败：{}", message);
                closeConnection();
                return false;
            }
        } catch (Exception e) {
            log.error("[NettyClientManager]发送消息异常", e);
            closeConnection();
            return false;
        }
    }

    /**
     * 检查是否已连接
     */
    public boolean isConnected() {
        return channel != null && channel.isActive();
    }

    /**
     * 关闭连接
     */
    public void closeConnection() {
        lock.lock();
        try {
            if (channel != null && channel.isOpen()) {
                channel.close().sync();
                log.info("[NettyClientManager]Netty客户端连接已关闭");
            }
            if (group != null) {
                group.shutdownGracefully().sync();
                log.info("[NettyClientManager]Netty客户端EventLoopGroup已关闭");
            }
        } catch (Exception e) {
            log.error("[NettyClientManager]关闭Netty连接异常", e);
        } finally {
            channel = null;
            group = null;
            lock.unlock();
        }
    }

    /**
     * 调度重连任务
     */
    private void scheduleReconnect() {
        if (group == null || group.isShuttingDown() || group.isTerminated()) {
            return;
        }
        if (reconnectCount >= MAX_RECONNECT_COUNT) {
            log.warn("已达最大重连次数({}次)，暂停重连", MAX_RECONNECT_COUNT);
            return;
        }
        reconnectCount++;
        group.schedule(() -> {
            log.info("尝试重新连接Netty服务器第{}次尝试重连...", reconnectCount);
            asyncInitConnection();
        }, reconnectDelay, TimeUnit.SECONDS);
    }

    /**
     * 销毁资源（程序退出时调用）
     */
    @PreDestroy
    public void destroy() {
        closeConnection();
        log.info("[NettyClientManager]实例已销毁");
    }
}